#pragma once
#include "../../../include/loopbuffer.hpp"
#include "../../../include/net_interface.hpp"
#include <WinSock2.h>
#include <Windows.h>


//socket ״̬
#define SOCKET_STATE_NONE       0
#define SOCKET_STATE_CONNECT    1
#define SOCKET_STATE_LISTEN     2
#define SOCKET_STATE_ESTABLISH  3
#define SOCKET_STATE_ERROR      4
#define SOCKET_STATE_TERMINATE  5
#define SOCKET_STATE_DELETE		6
#define SOCKET_STATE_ACCEPT     7

#define IOCP_OPT_RECV           0
#define IOCP_OPT_SEND           1
#define IOCP_OPT_ACCEPT         2
#define IOCP_OPT_CONNECT        3
#define IOCP_OPT_CONNECT_REQ    4
#define IOCP_OPT_ACCEPT_REQ     5

#define SOCKET_DELAY_CLOSE      50

struct IocpData
{
    OVERLAPPED  OverLapped;
    UINT8       Opt;
    WSABUF      WsaBuf;
};

class CIocpNetMgr;

class CIocpSocket
{
public:
    CIocpSocket(void);
    ~CIocpSocket(void);


    void InitIocpData(void);

    bool Send(const char* data, int len);
    void Close(ENetErrCode err_code);

    void Reset(void);

    bool PostSendReq(void);
    bool PostSend(void);
    void OnSend(BOOL ret, DWORD trans_byte);

    bool PostRecvReq(UINT32 last_data_len);
    bool PostRecv(void);
    void OnRecv(BOOL ret, DWORD trans_byte);
    
    bool PostConnectReq(bool reuse_addr);
    void ConnectEx(BOOL reuse_addr);
    void OnConnect(BOOL ret);

    //bool PostAcceptReq(void);
    //void AcceptEx(void);
    //void OnAccept(BOOL ret);

    void OnTimer(void);

    bool AllocDataBuf(INT32 recv_buf_size, INT32 send_buf_size);
    void FreeDataBuf(void);

    inline static CIocpSocket* GetSocketByRecvData(IocpData* recv_data){return (CIocpSocket*)((char*)recv_data - offsetof(CIocpSocket, m_iocp_recv_data));}
    inline static CIocpSocket* GetSocketBySendData(IocpData* send_data){return (CIocpSocket*)((char*)send_data - offsetof(CIocpSocket, m_iocp_send_data));}

    inline SOCKET GetSocket(void){return m_socket;}
    inline void SetSocket(SOCKET socket){m_socket = socket;}

    inline void* GetUserData(void){return m_user_data;}
    inline void SetUserData(void* user_data){m_user_data = user_data;}

    inline void SetState(LONG state){m_state = state;}
    inline LONG GetState(void){return m_state;}

    inline void SetPacketParser(IPacketParser* pkg_parser){m_pkg_parser = pkg_parser;}

    inline UINT32 GetPeerIP(void){return m_peer_ip;}
    inline UINT16 GetPeerPort(void){return m_peer_port;}

    inline UINT32 GetLocalIP(void){return m_local_ip;}
    inline UINT16 GetLocalPort(void){return m_local_port;}

    inline HTIMER GetTimer(void){return m_timer;}
    inline void SetTimer(HTIMER timer){m_timer = timer;}

    inline INT32 GetFreeSendCacheSize(void){return m_send_loop_buffer.GetFreeCount();}

public:
    SOCKET              m_socket;
    void*               m_user_data;

    char*               m_send_wsa_buf;
    char*               m_recv_wsa_buf;

    INT32               m_send_wsa_buf_size;
    INT32               m_recv_wsa_buf_size;

    IocpData            m_iocp_recv_data;
    IocpData            m_iocp_send_data;

    CLoopBuffer<char>   m_recv_loop_buffer;
    CLoopBuffer<char>   m_send_loop_buffer;

    LONG                m_state;

    LONG                m_post_recv;
    LONG                m_post_send;

    LONG				m_data_to_send;
    INT32               m_data_has_recv;

    INT32               m_data_delay_send;

    UINT32              m_local_ip;
    UINT16              m_local_port;

    UINT32              m_peer_ip;
    UINT16              m_peer_port;

    HTIMER              m_timer;

    IPacketParser*      m_pkg_parser;
    CIocpNetMgr*		m_iocp_net_mgr;
    INT32               m_delay_pkg_size;
};

class CIocpListener;

struct IocpListenData
{
    IocpData iocp_data;
    CIocpListener* listener;
    SOCKET accept_socket;
};

class CIocpListener
{
public:
    bool Listen(const char* ip, UINT16 port, bool bReUseAddr = false);
    bool PostAcceptEx(IocpListenData& iocp_listen_data);
    void OnAccept(BOOL ret, IocpListenData& iocp_listen_data);
    void Close(void);

    inline SOCKET GetSocket(void){return m_socket;}
    inline void SetSocket(SOCKET socket){m_socket = socket;}

    inline void SetState(LONG state){m_state = state;}
    inline LONG GetState(void){return m_state;}

    inline void* GetUserData(void){return m_user_data;}
    inline void SetUserData(void* user_data){m_user_data = user_data;}

public:
    SOCKET              m_socket;

    INT32               m_send_buf_size;
    INT32               m_recv_buf_size;

    UINT32              m_local_ip;
    UINT16              m_local_port;

    UINT32              m_peer_ip;
    UINT16              m_peer_port;

    IPacketParser*      m_pkg_parser;
    CIocpNetMgr*		m_iocp_net_mgr;

    char*               m_arry_addr_cache;
    IocpListenData*     m_arry_iocp_data;

    LONG                m_post_acceptex;

    LONG                m_state;
    void*               m_user_data;
protected:
private:
};